package com.njcb.ams.service.workflow;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.List;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;

import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.njcb.ams.portal.SysBaseDefine;
import com.njcb.ams.portal.SysBaseDefine.CharSet;
import com.njcb.ams.support.exception.ExceptionUtil;

/**
 * 流程设计
 * @author LOONG
 *
 */
@Service
public class ProcessDesignerService {
	@Autowired
	private ProcessEngine processEngine;
	@Autowired
	private ObjectMapper objectMapper;

	
	/**
	 * 新建一个空模型
	 * 
	 * @return
	 */
	@SuppressWarnings("deprecation")
	public String newModel() {
		RepositoryService repositoryService = processEngine.getRepositoryService();
		// 初始化一个空模型
		Model model = repositoryService.newModel();

		// 设置一些默认信息
		String key = "modelKey";
		String name = "modelName";
		String description = "";
		int revision = 1;
		
		ObjectNode modelNode = objectMapper.createObjectNode();
		modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);
		modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
		modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);

		model.setName(name);
		model.setKey(key);
		model.setMetaInfo(modelNode.toString());
		repositoryService.saveModel(model);
		String modelId = model.getId();

		// 完善ModelEditorSource
		ObjectNode editorNode = objectMapper.createObjectNode();
		editorNode.put("id", "canvas");
		editorNode.put("resourceId", "canvas");
		ObjectNode stencilSetNode = objectMapper.createObjectNode();
		stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
		editorNode.put("stencilset", stencilSetNode);
		try {
			repositoryService.addModelEditorSource(modelId, editorNode.toString().getBytes(CharSet.UTF8.value));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return modelId;
	}

	/**
	 * 获取流程模型
	 * @param id
	 * @return
	 */
	public List<Model> modelList() {
		RepositoryService repositoryService = processEngine.getRepositoryService();
		List<Model> models = repositoryService.createModelQuery().list();
		return models;
	}

	/**
	 * 删除流程模型
	 * @param id
	 * @return
	 */
	public void deleteModel(String modelId) {
		RepositoryService repositoryService = processEngine.getRepositoryService();
		repositoryService.deleteModel(modelId);
	}

	/**
	 * 发布流程模型
	 * @param id
	 * @return
	 * @throws Exception
	 */
	public void deploy(String modelId) throws Exception {
		// 获取模型
		RepositoryService repositoryService = processEngine.getRepositoryService();
		Model modelData = repositoryService.getModel(modelId);
		byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());

		if (bytes == null) {
			ExceptionUtil.throwAppException("模型数据为空，请先设计流程并成功保存，再进行发布。");
		}

		JsonNode modelNode = new ObjectMapper().readTree(bytes);

		BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
		if (model.getProcesses().size() == 0) {
			ExceptionUtil.throwAppException("数据模型不符要求，请至少设计一条主线流程。");
		}
		byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);

		// 发布流程
		String processName = modelData.getName() + ".bpmn";
		Deployment deployment = repositoryService.createDeployment().name(modelData.getName())
				.addString(processName, new String(bpmnBytes, CharSet.UTF8.value)).deploy();
		modelData.setDeploymentId(deployment.getId());
		repositoryService.saveModel(modelData);
	}
	
	/**
	 * 导出流程模型
	 * @param id
	 * @return
	 * @throws Exception
	 */
	public String export(String modelId) throws Exception {
		// 获取模型
		RepositoryService repositoryService = processEngine.getRepositoryService();
		Model modelData = repositoryService.getModel(modelId);
		byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());

		if (bytes == null) {
			ExceptionUtil.throwAppException("模型数据为空，请先设计流程并成功保存，再进行发布。");
		}
		JsonNode modelNode = new ObjectMapper().readTree(bytes);

		BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
		if (model.getProcesses().size() == 0) {
			ExceptionUtil.throwAppException("数据模型不符要求，请至少设计一条主线流程。");
		}
		byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);
		// 发布流程
		String processName = SysBaseDefine.SYS_FILE_TMP_PATH + modelData.getName() + ".bpmn";
		File file = new File(processName);
		FileOutputStream fos = new FileOutputStream(new File(processName));
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		bos.write(bpmnBytes);
		bos.close();
		return file.getPath();
	}
	
	/**
	 * 导入流程模型
	 * @param fileName
	 * @param bpmnfile
	 * @return
	 * @throws Exception
	 */
	public void importModel(String fileName, String bpmnFilePath) throws Exception {
		File tmpbpmnfile = new File(bpmnFilePath);
        FileInputStream fis = new FileInputStream(tmpbpmnfile);
        //转化为bpmnModel
    	InputStreamReader in = new InputStreamReader(fis, CharSet.UTF8.value);
    	XMLStreamReader xmlsr = XMLInputFactory.newInstance().createXMLStreamReader(in);
    	BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xmlsr);
    	//转为json
    	ObjectNode objectNode = new BpmnJsonConverter().convertToJson(bpmnModel);
    	byte[] jsonBytes = objectNode.toString().getBytes();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Model modelData = repositoryService.newModel();
        
        modelData.setName(fileName);
        modelData.setKey("导入key");
        repositoryService.saveModel(modelData);
        repositoryService.addModelEditorSource(modelData.getId(), jsonBytes);
	}
}
